#pragma once

#include <iostream>
#include <memory>
#include <vector>
#include <errno.h>
#include <cstring>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include "LogMessage.hpp"
#include "Socket.hpp"

const int defaultsize = 100;

class SelectServer
{
public:
    SelectServer(uint16_t port)
    {
        _listenSock = new TcpSocket;
        _listenSock->CreateBindListenSocket(port);

        _sockets.resize(defaultsize);
        for (int i = 0; i < _sockets.size(); ++i)
            _sockets[i] = nullptr;

        _sockets[0] = _listenSock;
    }

    ~SelectServer()
    {
        _listenSock->CloseSockfd();
        delete _listenSock;
    }

    void Start()
    {
        while (true)
        {
            FD_ZERO(&_rfds);
            int max = _listenSock->GetSockfd();
            for (int i = 0; i < _sockets.size(); i++)
            {
                if (_sockets[i] != nullptr)
                {
                    FD_SET(_sockets[i]->GetSockfd(), &_rfds);
                    if (_sockets[i]->GetSockfd() > max)
                        max = _sockets[i]->GetSockfd();
                }
            }
            PrintDebug();
            struct timeval _timeout = { 2, 0 };

            int n = select(max + 1, &_rfds, nullptr, nullptr, &_timeout);
            if (n == 0)
            {
                lg.LogMessage(Debug, "time out, Please try again time: %d", _timeout.tv_sec);
            }
            else if (n == -1)
            {
                lg.LogMessage(Warning, "error, errno: %d  strerror: %s", errno, strerror(errno));
            }
            else
            {
                lg.LogMessage(Debug, "Ready in order");
                Handler(n);
            }
        }
    }

    void Handler(int count)
    {
        for (int i = 0; i < _sockets.size(); i++)
        {
            if (count == 0)
                break;

            if (_sockets[i] == nullptr)
                continue;

            if (FD_ISSET(_sockets[i]->GetSockfd(), &_rfds))
            {
                count--;
                if (_sockets[i]->GetSockfd() == _listenSock->GetSockfd())
                {
                    // 新连接到来
                    InetAddr addr;
                    Socket *sockfd = _listenSock->AcceptConnect(addr);
                    lg.LogMessage(Debug, "sockfd: %d link success %s", sockfd->GetSockfd(), addr.GetUser().c_str());

                    int posi = 0;
                    for (posi = 0; posi < _sockets.size(); posi++)
                    {
                        if (_sockets[posi] == nullptr)
                        {
                            _sockets[posi] = sockfd;
                            break;
                        }
                    }
                    if (posi == _sockets.size())
                    {
                        lg.LogMessage(Debug, "The number of connections is full");
                    }

                }
                else
                {
                    // 正常的读事件
                    std::string buffer;
                    InetAddr addr;
                    int n = _sockets[i]->Recvfrom(buffer, &addr);
                    if (n > 0)
                    {   
                        lg.LogMessage(Debug, "%s send: %s", addr.GetUser().c_str(), buffer.c_str());
                    }
                    else if (n == 0)
                    {
                        _sockets[i]->CloseSockfd();
                        delete _sockets[i];
                        _sockets[i] = nullptr;
                        lg.LogMessage(Debug, "you close connect, me too");
                    }
                    else 
                    {
                        lg.LogMessage(Warning, "error, errno: %d  strerror: %s", errno, strerror(errno));
                    }
                }
            }
        }
    }

    void PrintDebug()
    {
        std::cout << "Ready in order fd: ";
        for (int i = 0; i < _sockets.size(); i++)
        {
            if (_sockets[i] != nullptr)
            {
                std::cout <<_sockets[i]->GetSockfd() << " ";
            }
        }
        std::cout << std::endl;
    }

private:
    TcpSocket *_listenSock;
    std::vector<Socket *> _sockets;
    fd_set _rfds;
};